package com.ruoyi.framework.web.service;

import javax.annotation.Resource;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.KaurConstants;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.model.UserPhonePo;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.http.Http5Util;
import com.ruoyi.system.service.ISysRoleService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.BlackListException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录校验方法
 *
 * @author ruoyi
 */
@Component
public class SysLoginService {
    @Autowired
    private TokenService tokenService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private ISysRoleService roleService;

    /**
     * 登录验证
     *
     * @return 结果
     */
    public String login(LoginBody loginBody) {
        String username = loginBody.getUsername();
        String password = loginBody.getPassword();
        String openId = loginBody.getOpenId();
        String openSecond = loginBody.getOpenSecond();

//        //验证码校验
//        validateCaptcha(username, code, uuid);
//        // 登录前置校验
        loginPreCheck(username, password);  // 用户输入检查
        // 用户验证
        Authentication authentication = null;
        try {
            // 判断输入的是账号还是电话号码
            String principal = username;
            if (isPhoneNumber(username)) {
                principal = getUsernameByPhoneNumber(username); // 根据电话号码获取对应的用户名
            }

            // 创建认证令牌，允许使用账号或电话号码
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(principal, password);

            AuthenticationContextHolder.setContext(authenticationToken);

            // 该方法会去调用 UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }

// 获取登录的用户信息
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());

        //修改openId
        SysUser sysUser = userService.selectUserById(loginUser.getUserId());
        if (openId != null && !openId.equals(sysUser.getOpenId())) {
            SysUser userUpdate = new SysUser();
            userUpdate.setUserId(sysUser.getUserId());
            userUpdate.setOpenId(openId);
            userUpdate.setOpenSecond(openSecond);
            userUpdate.setUpdateTime(DateUtils.getNowDate());
            userService.updateUserStatus(userUpdate);
        }

// 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     * 判断是否为电话号码：
     *
     * @param input 电话号码或者用户名
     * @return
     */
    private boolean isPhoneNumber(String input) {
        // 简单判断输入是否为有效的电话号码，例如长度为 11 位且全是数字（具体规则根据实际需求调整）
        return input != null && input.matches("^\\d{11}$");
    }

    /**
     * 根据电话号码查询用户名：
     *
     * @param phoneNumber 电话号码
     * @return
     */
    private String getUsernameByPhoneNumber(String phoneNumber) {
        // 调用数据库查询接口，获取手机号对应的用户名
        SysUser user = userService.selectUserByPhone(phoneNumber);
        return user != null ? user.getUserName() : null;
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public void validateCaptcha(String username, String code, String uuid) {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        if (captchaEnabled) {
            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
            String captcha = redisCache.getCacheObject(verifyKey);
            if (captcha == null) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
                throw new CaptchaExpireException();
            }
            redisCache.deleteObject(verifyKey);
            if (!code.equalsIgnoreCase(captcha)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                throw new CaptchaException();
            }
        }
    }

    /**
     * 登录前置校验
     *
     * @param username 用户名
     * @param password 用户密码
     */
    public void loginPreCheck(String username, String password) {
        // 用户名或密码为空 错误
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
            throw new UserNotExistsException();
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }
        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }
        // IP黑名单校验
        String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
            throw new BlackListException();
        }
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }


    public String temporaryTokenJustOnce(Long userId) {
        SysUser user = userService.selectUserById(userId);
        if (user == null) {
            throw new ServiceException("该用户不存在");
        }
        LoginUser loginUser = new LoginUser();
        loginUser.setUser(user);
        loginUser.setUseTime(1);
        return tokenService.createToken(loginUser);
    }

    /**
     * 电话号码密码登录
     *
     * @param po 请求参数
     * @return token
     */
    public LoginUser appLogin(UserPhonePo po) {
        validateAppLoginPo(po);
//        String decryptPhone;
//        try {
//            decryptPhone = AESUtil.decrypt(po.getPhone());
//        } catch (Exception e) {
//            throw new ServiceException("解密失败" + e.getMessage());
//        }
        SysUser user = userService.selectUserByUserName(po.getPhone());
        if (user == null) {
            SysUser sysUser = new SysUser();
            LoginUser loginUser = new LoginUser();
            sysUser.setNickName("普通用户" + OrderUtils.getRandom(10L));
            sysUser.setUserName(po.getPhone());
            sysUser.setEmail("");
            sysUser.setPhonenumber(po.getPhone());
            sysUser.setSex("2");
            sysUser.setAvatar(KaurConstants.DEFAULT_AVATAR);
            sysUser.setPassword("");
            sysUser.setStatus("0");
            sysUser.setDelFlag("0");
            sysUser.setLoginDate(new Date());
            sysUser.setRoleIds(new Long[]{5L});
            userService.insertUser(sysUser);
            sysUser.setRoles(roleService.listRolesByUserId(sysUser.getUserId()));
            loginUser.setUser(sysUser);
            loginUser.setUserId(sysUser.getUserId());
            loginUser.setToken(tokenService.createToken(loginUser));
            return loginUser;
        } else {
            CullenUtils.validateDataThrowException("1".equals(user.getStatus()), "账户已停用...");
            LoginUser loginUser = new LoginUser();
            user.setRoles(roleService.listRolesByUserId(user.getUserId()));
            loginUser.setUser(user);
            loginUser.setUserId(user.getUserId());
            loginUser.setToken(tokenService.createToken(loginUser));
            return loginUser;
        }
    }

    /**
     * 校验
     *
     * @param po 请求参数
     */
    private void validateAppLoginPo(UserPhonePo po) {
        CullenUtils.validateDataThrowException(po == null, "请输入登录信息...");
    }


    /**
     * code获取小程序参数
     *
     * @param code code
     * @return JSONObject
     */
    @SneakyThrows
    public JSONObject appletGetOpenId(String code, String appId, String secret) {
        Map<String, String> requestUrlParam = new HashMap<>(4);
        requestUrlParam.put("appid", appId);
        requestUrlParam.put("secret", secret);
        requestUrlParam.put("js_code", code);
        requestUrlParam.put("grant_type", "authorization_code");
        JSONObject json = com.alibaba.fastjson2.JSON.parseObject(Http5Util.postStr(KaurConstants.APPLET_REQUEST_URL, requestUrlParam));
        CullenUtils.validateDataThrowException(json.get("openid") == null, "code已过期，请稍后再试...");
        return json;
    }


}
